﻿using System;
using System.Net;
using System.Windows.Forms;
using DotRas;
using System.Data;
using MySql;
using MySql.Data.MySqlClient;
using MySql.Data;
using System.Net.NetworkInformation;
using System.Text;
namespace DotRas.Samples.CreateAndDialVpnEntry
{
    public partial class MainForm : Form
    {
        /// <summary>
        /// Defines the name of the entry being used by the example.
        /// </summary>
        public const string EntryName = "DeepinVPN";
        public string ServerIpAddress = "";
        /// <summary>
        /// Holds a value containing the handle used by the connection that was dialed.
        /// </summary>
        private RasHandle handle = null;

        public MainForm()
        {
            this.InitializeComponent();         
            
            
        }
        /// <summary>
        /// 绑定GridViewServer表
        /// </summary>
        private void bindGridViewServer()
        {
            string ServerSql = "SELECT  id,server.serverdesc,server.ipaddress,server.name,server.id,server.L2tp_Port,server.openvpn_port,server.pptp_port,server.enable from server where enable='true'";
            DataSet ds = new DataSet();
            ds = MySqlHelper.GetDataSet(MySqlHelper.Conn, CommandType.Text, ServerSql);
            listBoxLine.Items.Add(ds.Tables[0].Rows.Count.ToString());
            GridViewServerList.Rows.Clear();
            for (int i = 0; i < ds.Tables[0].Rows.Count;i++ )
            {
                listBoxLine.Items.Add(ds.Tables[0].Rows[i][1].ToString());
                GridViewServerList.Rows.Add();
                GridViewServerList.Rows[i].Cells["ServerName"].Value = ds.Tables[0].Rows[i][1].ToString();
                GridViewServerList.Rows[i].Cells["ipaddress"].Value = ds.Tables[0].Rows[i][2].ToString();
                GridViewServerList.Rows[i].Cells["OnlineCount"].Value = CountOnline(ds.Tables[0].Rows[i][2].ToString());
                //GridViewServerList.Rows[i].Cells[1].Value = ds.Tables[0].Rows[i][1].ToString();
                // GridViewServerList.Rows[i].Cells[2].Value = ds.Tables[0].Rows[i][0].ToString();
            }
            if (GridViewServerList.RowCount > 0)
            {
                GridViewServerList.Rows[1].Selected = true;
                lblCurrentNodeText.Text = GridViewServerList.SelectedRows[0].Cells["ServerName"].Value.ToString();
                ServerIpAddress = GridViewServerList.SelectedRows[0].Cells["ipaddress"].Value.ToString();

            }
            ds.Clear();
            ds.Dispose();
            TestDelay();

        }
        private string CountOnline(string ServerIP)
        {
           // string OnLineSql = "select count(*) from radacct where nasipaddress='127.0.0.1'" + " and acctstoptime is NULL";
            if(ServerIP=="108.61.163.169")
            {
                ServerIP = "127.0.0.1";
            }
            string OnLineSql = "select count(*) from radacct where nasipaddress='"+ServerIP+"'"+" and acctstoptime is NULL";
            return MySqlHelper.ExecuteScalar(MySqlHelper.Conn,CommandType.Text,OnLineSql).ToString();

        }
        /// <summary>
        /// Occurs when the user clicks the Create Entry button.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">An <see cref="System.EventArgs"/> containing event data.</param>
        private void CreateEntryButton_Click(object sender, EventArgs e)
        {            
            // This opens the phonebook so it can be used. Different overloads here will determine where the phonebook is opened/created.
            // Create the entry that will be used by the dialer to dial the connection. Entries can be created manually, however the static methods on
            // the RasEntry class shown below contain default information matching that what is set by Windows for each platform.
            if (ServerIpAddress != "")
            {
                if (CheckEntryExist(EntryName))
                {
                    DeleteVpnEntry(EntryName);
                }
                this.AllUsersPhoneBook.Open();
                RasEntry entry = RasEntry.CreateVpnEntry(EntryName, ServerIpAddress, RasVpnStrategy.PptpFirst, RasDevice.GetDeviceByName("(PPTP)", RasDeviceType.Vpn));
                //RasEntry entry = RasEntry.CreateVpnEntry(EntryName, IPAddress.Loopback.ToString(), RasVpnStrategy.Default,
                //  RasDevice.GetDeviceByName("(PPTP)", RasDeviceType.Vpn));
                // Add the new entry to the phone book.aa
                this.AllUsersPhoneBook.Entries.Add(entry);
                // StatusTextBox.AppendText(this.AllUsersPhoneBook.Entries.Contains("test").ToString());
                CheckEntryExist(EntryName);
            }
        }
        /// <summary>
        /// 删除已在的VPN链接EntryName
        /// </summary>
        private void DeleteVpnEntry(string VpnName)
        {
            RasPhoneBook rasPhoneBook = new RasPhoneBook();            
            RasPhoneBook rasPhoneBookAll = new RasPhoneBook();           
            var phoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.User);
            var phoneBookPathAllUsers = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers);
            rasPhoneBook.Open(phoneBookPath);
            rasPhoneBookAll.Open(phoneBookPathAllUsers);
            if (rasPhoneBook.Entries.Contains(VpnName))
            {
                rasPhoneBook.Entries.Remove(VpnName);
                listBoxLine.Items.Add(VpnName + "-Deleted");
            }

            if (rasPhoneBookAll.Entries.Contains(VpnName))
            {
                rasPhoneBookAll.Entries.Remove(VpnName);
                listBoxLine.Items.Add(VpnName + "-Deleted");
            }        
        }
        /// <summary>
        /// 检查RasPhoneBook中是否存在EntryName.建立连接时会引发错误.
        /// </summary>
        /// <returns>存在返回True,不存在返回False</returns>
        /// 
        private bool CheckEntryExist(string EnName)
        {
            using (RasPhoneBook rasPhoneBook = new RasPhoneBook())
            {
                RasPhoneBook rasPhoneBookAll = new RasPhoneBook();
                //var phoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers);
                //var phoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.User); 
                var phoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.User);
                var phoneBookPathAllUsers = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers);
                rasPhoneBook.Open(phoneBookPath);
                rasPhoneBookAll.Open(phoneBookPathAllUsers);

                foreach (var entry in rasPhoneBookAll.Entries)
                {
                    listBoxLine.Items.Add(entry.Name);                   
                    
                }
                foreach (var entry in rasPhoneBook.Entries)
                {
                    listBoxLine.Items.Add(entry.Name); 
                 
                }
                if (rasPhoneBook.Entries.Contains(EnName))
                {
                    return true;                  
                    //rasPhoneBook.Entries.Remove(EntryName);
                }
                else
                {
                    if (rasPhoneBookAll.Entries.Contains(EnName))
                    {
                        listBoxLine.Items.Add("Yes"); 
                        return true;                         
                        //rasPhoneBookAll.Entries.Remove(EntryName);
                    }
                    else
                    {
                        return false;
                    }
                    
                }
               

            }
        
        }

        /// <summary>
        /// Occurs when the user clicks the Dial button.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">An <see cref="System.EventArgs"/> containing event data.</param>
        private void DialButton_Click(object sender, EventArgs e)
        {
            //this.StatusTextBox.Clear();

            // This button will be used to dial the connection.
            this.Dialer.EntryName = EntryName;
            this.Dialer.PhoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers);

            try
            {
                // Set the credentials the dialer should use.
                this.Dialer.Credentials = new NetworkCredential("sunlinsong", "sunwtw");

                // NOTE: The entry MUST be in the phone book before the connection can be dialed.
                // Begin dialing the connection; this will raise events from the dialer instance.
                this.handle = this.Dialer.DialAsync();

                // Enable the disconnect button for use later.
                this.DisconnectButton.Enabled = true;
            }
            catch (Exception ex)
            {
                //this.StatusTextBox.AppendText(ex.ToString());
                listBoxLine.Items.Add(ex.ToString()); 
            }
        }

        /// <summary>
        /// Occurs when the dialer state changes during a connection attempt.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">An <see cref="DotRas.StateChangedEventArgs"/> containing event data.</param>
        private void Dialer_StateChanged(object sender, StateChangedEventArgs e)
        {
            //this.StatusTextBox.AppendText(e.State.ToString() + "\r\n");
            listBoxLine.Items.Add(e.State.ToString()); 
        }

        /// <summary>
        /// Occurs when the dialer has completed a dialing operation.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">An <see cref="DotRas.DialCompletedEventArgs"/> containing event data.</param>
        private void Dialer_DialCompleted(object sender, DialCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                //this.StatusTextBox.AppendText("Cancelled!");
                listBoxLine.Items.Add("Cancelled!"); 
            }
            else if (e.TimedOut)
            {
                listBoxLine.Items.Add("Connection attempt timed out!");
            }
            else if (e.Error != null)
            {
                listBoxLine.Items.Add(e.Error.ToString());
            }
            else if (e.Connected)
            {
                listBoxLine.Items.Add("Connection successful!");
            }

            if (!e.Connected)
            {
                // The connection was not connected, disable the disconnect button.
                this.DisconnectButton.Enabled = false;
            }
        }

        /// <summary>
        /// Occurs when the user clicks the Disconnect button.
        /// </summary>
        /// <param name="sender">The object that raised the event.</param>
        /// <param name="e">An <see cref="System.EventArgs"/> containing event data.</param>
        private void DisconnectButton_Click(object sender, EventArgs e)
        {
            if (this.Dialer.IsBusy)
            {
                // The connection attempt has not been completed, cancel the attempt.
                this.Dialer.DialAsyncCancel();
            }
            else
            {
                // The connection attempt has completed, attempt to find the connection in the active connections.
                RasConnection connection = RasConnection.GetActiveConnectionByHandle(this.handle);
                if (connection != null)
                {
                    // The connection has been found, disconnect it.
                    connection.HangUp();
                    DeleteVpnEntry(EntryName);
                }
            }
        }
        private void Dissconnect()
        {
            if (this.Dialer.IsBusy)
            {
                // The connection attempt has not been completed, cancel the attempt.
                this.Dialer.DialAsyncCancel();
            }
            else
            {
                // The connection attempt has completed, attempt to find the connection in the active connections.
                RasConnection connection = RasConnection.GetActiveConnectionByHandle(this.handle);
                if (connection != null)
                {
                    // The connection has been found, disconnect it.
                    connection.HangUp();
                    DeleteVpnEntry(EntryName);
                }
            }
        
        }

        private void btnCheck_Click(object sender, EventArgs e)
        {
            if (CheckEntryExist(EntryName))
            {
                listBoxLine.Items.Add(EntryName+"存在");
            }
            else
            {
                listBoxLine.Items.Add(EntryName+"不存在");
            }       
        }

        private void MainForm_Load(object sender, EventArgs e)
        {

        }
        protected override void WndProc(ref Message m)
        {
            //Console.WriteLine(m.Msg);
            const int WM_SYSCOMMAND = 0x0112;
            const int SC_CLOSE = 0xF060;
            if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE)
            {
                //捕捉关闭窗体消息
                //用户点击关闭窗体控制按钮   注释为最小化窗体   
                //this.WindowState = FormWindowState.Minimized;
                if(MessageBox.Show("关闭程序会断开VPN链接!","关闭程序",MessageBoxButtons.OKCancel)==DialogResult.OK)
                {
                    //   Dissconnect();
                    this.Close();
                }
             //   Dissconnect();
                //窗体隐藏
                //this.Hide();
                return;
            }
            base.WndProc(ref m);
        }

        private void btnTestSpeed_Click(object sender, EventArgs e)
        {
            bindGridViewServer();
        }

        private void btnPing_Click(object sender, EventArgs e)
        {
            TestDelay();
        }
        /// <summary>
        /// 调用Ping测试服务器延迟.
        /// </summary>
        /// <param name="ServerIP"></param>
        private void TestDelay()
        {
            string ServerIP;
            for (int i = 0; i < GridViewServerList.Rows.Count; i++)
            {
                ServerIP=GridViewServerList.Rows[i].Cells["ipaddress"].Value.ToString();
                Ping p1 = new Ping();
                p1.PingCompleted += new PingCompletedEventHandler(this.PingCompletedCallBack);//设置PingCompleted事件处理程序 
                p1.SendAsync(ServerIP, null);
            }
        }
        /// <summary>
        /// 异步处理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PingCompletedCallBack(object sender, PingCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
               listBoxLine.Items.Add("Ping Canncel");
                return;
            }
            if (e.Error != null)
            {
                listBoxLine.Items.Add(e.Error.Message);
                return;

            }
            //StringBuilder sbuilder;
            PingReply reply = e.Reply;
            if (reply.Status == IPStatus.Success)
            {              
                for (int i = 0; i < GridViewServerList.Rows.Count; i++)
                {
                    if (reply.Address.ToString()==GridViewServerList.Rows[i].Cells["ipaddress"].Value.ToString())
                    {
                        GridViewServerList.Rows[i].Cells["DelayTime"].Value = reply.RoundtripTime.ToString();
                    }
                }

            }
        }
        private void GridViewServerList_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            lblCurrentNodeText.Text = GridViewServerList.CurrentRow.Cells["ServerName"].Value.ToString();
            ServerIpAddress = GridViewServerList.SelectedRows[0].Cells["ipaddress"].Value.ToString();
        }
        
    }
}
